package com.iwhalecloud.citybrain.flow.platform.client;

import java.util.Objects;

import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpUtil;
import com.iwhalecloud.citybrain.flow.platform.client.util.GsonHelperUtils;
import com.iwhalecloud.citybrain.flow.platform.client.util.HttpClientUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ResponseResult;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpAbortProcessInstanceDto;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpApplyProcessDto;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpCommandResultDto;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpCompleteWorkItemDto;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpCreateProcessInstanceDto;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpGetProcessGraphDto;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpGetProcessXmlDto;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpMyApplyQueryDto;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpStartProcessInstanceDto;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpTaskListQueryDto;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpTerminateProcessInstanceDto;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author lilh
 * @date 2019-01-22 10:57
 */
public class FlowHttpClient {

    private static final Logger logger = LoggerFactory.getLogger(FlowHttpClient.class);
    private String serverUrl;
    private String commonUrl;


    public FlowHttpClient() {
        this.serverUrl = resolveDefaultServerUrl();
        this.commonUrl = this.serverUrl + "/restful/call";
    }

    private ResponseResult sendMsg(String httpUrl, String paramJson) {
        String resultJson;

        try {
            resultJson = HttpClientUtils.sendHttpPost(httpUrl, paramJson);
            return getResponseResult(resultJson);
        } catch (RuntimeException e) {
            logger.error("-----调用流程http服务异常，异常原因：" + e.getMessage(), e);
            throw e;
        }
    }

    private ResponseResult get(String url) {
        try {
            String result = HttpUtil.get(url);
            return getResponseResult(result);
        } catch (RuntimeException e) {
            logger.error("调用服务失败，异常原因：{}", e.getMessage());
            throw e;
        }
    }

    private ResponseResult post(String url, String json) {
        try {
            String result = HttpUtil.post(url, json);
            return getResponseResult(result);
        } catch (RuntimeException e) {
            logger.error("调用服务失败，异常原因：{}", e.getMessage());
            throw e;
        }
    }

    /**
     * 创建流程实例
     *
     * @param createProcessInstanceDto 参数dto
     * @return 处理结果
     */
    public HttpCommandResultDto createProcessInstance(HttpCreateProcessInstanceDto createProcessInstanceDto) {
        String paramJson = GsonHelperUtils.toJson(createProcessInstanceDto);
        logger.info("----创建流程实例参数：" + paramJson);
        ResponseResult result = this.sendMsg(this.serverUrl + "/api/v1.0/public/createProcessInstance", paramJson);
        logger.info("----创建流程实例返回结果：" + result);
        HttpCommandResultDto resultDto = this.getCommandResultDtoFromJson(GsonHelperUtils.toJson(result.getDatas()));
        return resultDto;
    }

    /**
     * 启动流程实例
     *
     * @param startProcessInstanceDto 参数dto
     * @return 处理结果
     */
    public HttpCommandResultDto startProcessInstance(HttpStartProcessInstanceDto startProcessInstanceDto) {
        String paramJson = GsonHelperUtils.toJson(startProcessInstanceDto);
        logger.info("----启动流程实例参数：" + paramJson);
        ResponseResult result = this.sendMsg(this.serverUrl + "/api/v1.0/public/startProcessInstance", paramJson);
        logger.info("----启动流程实例返回结果：" + result);
        HttpCommandResultDto resultDto = this.getCommandResultDtoFromJson(GsonHelperUtils.toJson(result.getDatas()));
        return resultDto;
    }

    /**
     * 办理任务工单
     *
     * @param completeWorkItemDto 参数dto
     * @return 处理结果
     */
    public HttpCommandResultDto completeWorkItem(HttpCompleteWorkItemDto completeWorkItemDto) {
        String paramJson = GsonHelperUtils.toJson(completeWorkItemDto);
        logger.info("----办理任务参数：" + paramJson);
        ResponseResult result = this.sendMsg(this.serverUrl + "/api/v1.0/public/completeWorkItem", paramJson);
        logger.info("----办理任务返回结果：" + result);
        HttpCommandResultDto resultDto = this.getCommandResultDtoFromJson(GsonHelperUtils.toJson(result.getDatas()));
        return resultDto;
    }

    /**
     * 查询任务列表
     *
     * @param taskListQueryDto 查询参数
     * @return 任务列表
     */
    public HttpCommandResultDto listTasks(HttpTaskListQueryDto taskListQueryDto) {
        if (!validate(taskListQueryDto)) {
            return HttpCommandResultDto.error("参数缺失");
        }
        String paramJson = GsonHelperUtils.toJson(taskListQueryDto);
        logger.info("----查询任务列表参数：" + paramJson);
        ResponseResult result = this.sendMsg(this.serverUrl + "/api/v1.0/public/listTask", paramJson);
        logger.info("----查询任务列表返回结果：" + result);
        HttpCommandResultDto resultDto = this.getCommandResultDtoFromJson(GsonHelperUtils.toJson(result.getDatas()));
        return resultDto;
    }

    /**
     * 查询我的申请单列表
     *
     * @param myApplyQueryDto 查询参数
     * @return 申请单列表
     */
    public HttpCommandResultDto listMyApply(HttpMyApplyQueryDto myApplyQueryDto) {
        if (!validate(myApplyQueryDto)) {
            return HttpCommandResultDto.error("参数缺失");
        }
        logger.info("----查询申请列表参数：" + GsonHelperUtils.toJson(myApplyQueryDto));
        String paramJson = GsonHelperUtils.toJson(myApplyQueryDto);
        ResponseResult result = this.sendMsg(this.serverUrl + "/api/v1.0/public/myApply", paramJson);
        logger.info("----查询申请列表返回结果：" + GsonHelperUtils.toJson(result));
        HttpCommandResultDto resultDto = this.getCommandResultDtoFromJson(GsonHelperUtils.toJson(result.getDatas()));
        return resultDto;
    }

    private boolean validate(HttpMyApplyQueryDto myApplyQueryDto) {
        return Objects.nonNull(myApplyQueryDto) && StringUtils.isNotBlank(myApplyQueryDto.getStarterId());
    }

    private boolean validate(HttpTaskListQueryDto taskListQueryDto) {
        //appCode和assignee不能同时为空
        return Objects.nonNull(taskListQueryDto)
                && (StringUtils.isNotBlank(taskListQueryDto.getAssignee())
                || StringUtils.isNotBlank(taskListQueryDto.getAppCode()));
    }

    /**
     * 终止流程
     *
     * @param httpTerminateProcessInstanceDto 参数dto
     * @return 处理结果
     */
    public HttpCommandResultDto terminateProcessInstance(HttpTerminateProcessInstanceDto httpTerminateProcessInstanceDto) {
        logger.info("----终止流程参数：" + GsonHelperUtils.toJson(httpTerminateProcessInstanceDto));
        String paramJson = GsonHelperUtils.toJson(httpTerminateProcessInstanceDto);
        ResponseResult result = this.sendMsg(this.serverUrl + "/api/v1.0/public/terminateProcessInstance", paramJson);
        logger.info("----终止流程返回结果：" + GsonHelperUtils.toJson(result));
        HttpCommandResultDto resultDto = this.getCommandResultDtoFromJson(GsonHelperUtils.toJson(result.getDatas()));
        return resultDto;
    }


    /**
     * 作废流程实例
     *
     * @param abortProcessInstanceDto 参数dto
     * @return 处理结果
     */
    public HttpCommandResultDto abortProcessInstance(HttpAbortProcessInstanceDto abortProcessInstanceDto) {
        String paramJson = GsonHelperUtils.toJson(abortProcessInstanceDto);
        logger.info("----终止流程参数：" + paramJson);
        ResponseResult result = this.sendMsg(this.serverUrl + "/api/v1.0/public/terminateProcessInstance", paramJson);
        logger.info("----终止流程返回结果：" + result);
        HttpCommandResultDto resultDto = this.getCommandResultDtoFromJson(GsonHelperUtils.toJson(result.getDatas()));
        return resultDto;
    }

    /**
     * 生成流程图
     *
     * @param processGraphDto 参数
     * @return 流程图信息
     */
    public ResponseResult generateProcessDiagram(HttpGetProcessGraphDto processGraphDto) {
        if (Objects.isNull(processGraphDto) || Objects.isNull(processGraphDto.getProcessInstanceId())) {
            throw new IllegalArgumentException("参数缺失");
        }
        String paramJson = GsonHelperUtils.toJson(processGraphDto);
        logger.info("----生成流程图：" + paramJson);
        ResponseResult result = this.sendMsg(this.serverUrl + "/api/v1.0/public/generateProcessDiagram", paramJson);
        logger.info("----生成流程图返回结果：" + result);
        return result;
    }

    /**
     * 生成流程xml
     *
     * @param processXmlDto 参数
     * @return 流程xml信息,base64编码
     */
    public ResponseResult generateProcessXml(HttpGetProcessXmlDto processXmlDto) {
        if (Objects.isNull(processXmlDto) || Objects.isNull(processXmlDto.getProcessInstanceId())) {
            throw new IllegalArgumentException("参数缺失");
        }
        String paramJson = GsonHelperUtils.toJson(processXmlDto);
        logger.info("----生成流程xml：" + paramJson);
        ResponseResult result = this.sendMsg(this.serverUrl + "/api/v1.0/public/generateProcessXml", paramJson);
        logger.info("----生成流程xml返回结果：" + result);
        return result;
    }

    /**
     * 发起流程
     *
     * @param applyProcessDto 参数dto
     * @return 处理结果
     */
    public HttpCommandResultDto applyProcess(HttpApplyProcessDto applyProcessDto) {
        logger.info("----发起流程参数：{}", GsonHelperUtils.toJson(applyProcessDto));
        String paramJson = GsonHelperUtils.toJson(applyProcessDto);
        ResponseResult result = this.sendMsg(this.serverUrl + "/api/v1.0/public/applyProcess", paramJson);
        logger.info("---- 发起申请返回：{}", GsonHelperUtils.toJson(result));
        HttpCommandResultDto resultDto = this.getCommandResultDtoFromJson(GsonHelperUtils.toJson(result.getDatas()));
        return resultDto;
    }

    /**
     * 获取模型关联的表单schema
     *
     * @param modelKey 流程编码
     * @return 表单schema
     */
    public ResponseResult getStartForm(String modelKey) {
        Assert.notNull(modelKey);
        logger.debug("获取模型表单schema: {}", modelKey);
        ResponseResult result = this.get(this.serverUrl + "/api/v1.0/public/getStartForm?modelKey=" + modelKey);
        logger.debug("获取模型表单schema返回结果：{}", GsonHelperUtils.toJson(result));
        return result;
    }

    /**
     * 获取模型关联的表单schema + 表单数据
     *
     * @param processInstanceId 流程实例id
     * @return 表单schema + 表单数据
     */
    public ResponseResult getStartFormWithData(String processInstanceId) {
        Assert.notNull(processInstanceId);
        logger.debug("获取模型表单schema+表单数据: {}", processInstanceId);
        ResponseResult result = this.get(this.serverUrl + "/api/v1.0/public/getStartFormWithData?processInstanceId=" + processInstanceId);
        logger.debug("获取模型表单schema+表单数据返回结果：{}", GsonHelperUtils.toJson(result));
        return result;
    }

    /**
     * 获取任务关联的表单schema
     *
     * @param taskId 任务id
     * @return 表单schema
     */
    public ResponseResult getTaskForm(String taskId) {
        Assert.notNull(taskId);
        logger.debug("获取任务关联表单schema: {}", taskId);
        ResponseResult result = this.get(this.serverUrl + "/api/v1.0/public/getTaskForm?taskId=" + taskId);
        logger.debug("获取任务关联表单schema返回结果：{}", GsonHelperUtils.toJson(result));
        return result;
    }

    /**
     * 获取任务关联的表单schema + 表单数据
     *
     * @param taskId 任务id
     * @return 表单schema+表单数据
     */
    public ResponseResult getTaskFormWithData(String taskId) {
        Assert.notNull(taskId);
        logger.debug("获取任务关联表单schema+数据: {}", taskId);
        ResponseResult result = this.get(this.serverUrl + "/api/v1.0/public/getTaskFormWithData?taskId=" + taskId);
        logger.debug("获取任务关联表单schema+数据返回结果：{}", GsonHelperUtils.toJson(result));
        return result;
    }

    /**
     * 获取流程流转记录
     *
     * @param processInstanceId 流程实例id
     * @return 获取流程流转记录
     */
    public ResponseResult getFlowRecords(String processInstanceId) {
        Assert.notNull(processInstanceId);
        logger.debug("获取流程流转记录: {}", processInstanceId);
        ResponseResult result = this.get(this.serverUrl + "/api/v1.0/public/getFlowRecords?processInstanceId=" + processInstanceId);
        logger.debug("获取流程流转记录返回结果：{}", GsonHelperUtils.toJson(result));
        return result;
    }

    /**
     * 根据应用编码获取流程列表
     *
     * @param appCode 应用编码
     * @return 流程列表
     */
    public ResponseResult getModels(String appCode) {
        Assert.notNull(appCode);
        logger.debug("获取流程列表: {}", appCode);
        ResponseResult result = this.get(this.serverUrl + "/api/v1.0/public/getModels?appCode=" + appCode);
        logger.debug("获取流程列表：{}", GsonHelperUtils.toJson(result));
        return result;
    }

    /**
     * 根据实例id和任务节点编码获取填报的表单数据
     *
     * @param processInstanceId 实例id
     * @param taskNodeCode      任务节点编码
     * @return 表单数据列表
     */
    public ResponseResult getTaskFormWithData(String processInstanceId, String taskNodeCode) {
        Assert.notNull(processInstanceId);
        Assert.notNull(taskNodeCode);
        logger.debug("获取已填报的表单数据processInstanceId: {}， taskNodeCode: {}", processInstanceId, taskNodeCode);
        ResponseResult result = this.get(this.serverUrl + "/api/v1.0/public/getTaskFormWithDataByTaskNodeCode?processInstanceId=" + processInstanceId + "&taskNodeCode=" + taskNodeCode);
        logger.debug("获取已填报的表单数据结果：{}", GsonHelperUtils.toJson(result));
        return result;
    }


    public void setUrl(String serverUrl) {
        this.serverUrl = StringUtils.defaultIfBlank(serverUrl, resolveDefaultServerUrl());
        this.commonUrl = serverUrl + "/restful/call";
    }

    private HttpCommandResultDto getCommandResultDtoFromJson(String json) {
        HttpCommandResultDto commandResultDto = new HttpCommandResultDto();
        if (json != null && !"".equals(json)) {
            commandResultDto = GsonHelperUtils.parse(json, HttpCommandResultDto.class);
        }

        return commandResultDto;
    }

    private ResponseResult getResponseResult(String result) {

        return GsonHelperUtils.parse(Objects.requireNonNull(result), ResponseResult.class);

    }


    private String resolveDefaultServerUrl() {
        return "http://172.21.69.131:8080/flow-platform";
    }

}
